`timescale 1ns / 1ps
`include "const_def.vh"

module alu(
        //input
        input [31:0]        operandA,
        input [31:0]        operandB,

        //ctrl signal
        input [12:0]        ctrl_signal_alu,

        //output
        output [31:0]       ans

    );

    //T_ans
    reg[32:0]   T_ans;
    assign ans = T_ans[31:0];

    //compare operandA, operandB
    wire[31:0] cmp_ans;
    assign cmp_ans = (
               (operandA<operandB && operandA[31] == 0 && operandB[31] == 0) ||
               (operandA>operandB && operandA[31] == 1 && operandB[31] == 1) ||
               (operandA[31] == 1 && operandB[31] == 0)
           ) ? 32'b01 : 32'b00;


    always @ (*) begin
        if (ctrl_signal_alu==`ALU_OP_ADD)
            T_ans <= {operandA[31], operandA} + {operandB[31], operandB};

        else if (ctrl_signal_alu==`ALU_OP_SUB)
            T_ans <= {operandA[31], operandA} - {operandB[31], operandB};

        else if (ctrl_signal_alu==`ALU_OP_SLT)
            T_ans <= cmp_ans;

        else if (ctrl_signal_alu==`ALU_OP_AND)
            T_ans <= {operandA[31], operandA} & {operandB[31], operandB};

        else if (ctrl_signal_alu==`ALU_OP_NOR)
            T_ans <= ~({operandA[31], operandA} | {operandB[31], operandB});

        else if (ctrl_signal_alu==`ALU_OP_OR)
            T_ans <= {operandA[31], operandA} | {operandB[31], operandB};

        else if (ctrl_signal_alu==`ALU_OP_XOR)
            T_ans <= {operandA[31], operandA} ^ {operandB[31], operandB};

        else if (ctrl_signal_alu==`ALU_OP_SLL)
            T_ans <= {operandB[31], operandB} << operandA;

        else if (ctrl_signal_alu==`ALU_OP_SRL)
            T_ans <= {operandB[31], operandB} >> operandA;

        else if (ctrl_signal_alu==`ALU_OP_SRA)
            T_ans <= ({{31{operandB[31]}}, 1'b0} << (~operandA[4:0])) | (operandB >> operandA[4:0]);

        else if (ctrl_signal_alu==`ALU_OP_LUI)
            T_ans <= {operandB[15:0], 16'h0000};

        else if (ctrl_signal_alu==`ALU_OP_CLZ)
            T_ans <= operandA[31] ? 0 : operandA[30] ? 1 : operandA[29] ? 2 : operandA[28] ? 3 : operandA[27] ? 4 :
                  operandA[26] ? 5 : operandA[25] ? 6 : operandA[24] ? 7 : operandA[23] ? 8 : operandA[22] ? 9 :
                  operandA[21] ? 10 : operandA[20] ? 11 : operandA[19] ? 12 : operandA[18] ? 13 : operandA[17] ? 14 :
                  operandA[16] ? 15 : operandA[15] ? 16 : operandA[14] ? 17 : operandA[13] ? 18 : operandA[12] ? 19 :
                  operandA[11] ? 20 : operandA[10] ? 21 : operandA[9] ? 22 : operandA[8] ? 23 : operandA[7] ? 24 :
                  operandA[6] ? 25 : operandA[5] ? 26 : operandA[4] ? 27 : operandA[3] ? 28 : operandA[2] ? 29 :
                  operandA[1] ? 30 : operandA[0] ? 31 : 32;

        else if (ctrl_signal_alu==`ALU_OP_CLO)
            T_ans <= (~operandA[31]) ? 0 : (~operandA[30]) ? 1 : (~operandA[29]) ? 2 : (~operandA[28]) ? 3 : (~operandA[27]) ? 4 :
                  (~operandA[26]) ? 5 : (~operandA[25]) ? 6 : (~operandA[24]) ? 7 : (~operandA[23]) ? 8 : (~operandA[22]) ? 9 :
                  (~operandA[21]) ? 10 : (~operandA[20]) ? 11 : (~operandA[19]) ? 12 : (~operandA[18]) ? 13 : (~operandA[17]) ? 14 :
                  (~operandA[16]) ? 15 : (~operandA[15]) ? 16 : (~operandA[14]) ? 17 : (~operandA[13]) ? 18 : (~operandA[12]) ? 19 :
                  (~operandA[11]) ? 20 : (~operandA[10]) ? 21 : (~operandA[9]) ? 22 : (~operandA[8]) ? 23 : (~operandA[7]) ? 24 :
                  (~operandA[6]) ? 25 : (~operandA[5]) ? 26 : (~operandA[4]) ? 27 : (~operandA[3]) ? 28 : (~operandA[2]) ? 29 :
                  (~operandA[1]) ? 30 : (~operandA[0]) ? 31 : 32;

        else T_ans <= {operandB[31], operandB};
    end

endmodule
